package com.example.springboottest.example.guava.future.water;

import com.example.springboottest.util.Print;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import java.util.function.Supplier;

/**
 * 通过CompletableFuture实现
 * <p>
 * supplyAsync和supply 区别是同步和异步的区别，也就是是不是同一个线程执行的差别
 * <p>
 * thenApply、thenRun和thenAccept仨方法都是串行执行，区别是
 * thenApply  函数方法是Function和Function 也就是前方法返回值传到后方法，后方法有返回值
 * thenRun    函数方法是Runnable和Runnable 也就是前后方法没有返回值
 * thenAccept 函数方法是Function和Consumer 也就是前方法返回值传到后方法，后方法没有返回值
 * <p>
 * thenCompose功能上也是串行，但区别是将第二个任务所要调用的普通异步方法包装成一个CompletionStage异步实例
 * <p>
 * 对两个异步任务的合并处理需要用到thenCombine、runAfterBoth和thenAcceptBoth仨方法，区别是
 * thenCombine     函数方法是Function+Function和BiFunction   也就是前两个任务的函数是Function,把各自返回值传递给第3个任务BiFunction
 * runAfterBoth    函数方法是Runnable+Runnable和Runnable 也就是仨任务全部没有传入参数和返回值
 * thenAcceptBoth  函数方法是Function+Function和BiConsumer 也就是前方法返回值传到后方法，后方法没有返回值BiConsumer
 */
public class CompletableFutureDemo {
    public static final int SLEEP_GAP = 500;

    public static void main(String[] args) {
        ExecutorService jPool =
                Executors.newFixedThreadPool(10);
        CompletableFuture<Boolean> hotWaterfuture = CompletableFuture.supplyAsync(new Supplier<Boolean>() {
            @Override
            public Boolean get() {
                try {
                    Print.tcfo("洗好水壶");
                    Print.tcfo("灌上凉水");
                    Print.tcfo("放在火上");

                    //线程睡眠一段时间，代表烧水中
                    Thread.sleep(SLEEP_GAP);
                    Print.tcfo("水开了");

                } catch (InterruptedException e) {
                    Print.tcfo(" 发生异常被中断.");
                    return false;
                }
                Print.tcfo(" 运行结束.");

                return true;
            }
        }, jPool);

        CompletableFuture<Boolean> washFuture = CompletableFuture.supplyAsync(new Supplier<Boolean>() {
            @Override
            public Boolean get() {
                try {
                    Print.tcfo("洗茶壶");
                    Print.tcfo("洗茶杯");
                    Print.tcfo("拿茶叶");
                    //线程睡眠一段时间，代表清洗中
                    Thread.sleep(10 * SLEEP_GAP);
                    Print.tcfo("洗完了");

                } catch (InterruptedException e) {
                    Print.tcfo(" 清洗工作 发生异常被中断.");
                    return false;
                }
                Print.tcfo(" 清洗工作  运行结束.");
                return true;
            }
        }, jPool);

        CompletableFuture<Boolean> teaFuture = hotWaterfuture.thenCombineAsync(washFuture, new BiFunction<Boolean, Boolean, Boolean>() {
            @Override
            public Boolean apply(Boolean waterOk, Boolean cupOk) {
                if (waterOk && cupOk) {
                    Print.tcfo("泡茶喝");
                } else if (!waterOk) {
                    Print.tcfo("烧水失败，没有茶喝了");
                } else if (!cupOk) {
                    Print.tcfo("杯子洗不了，没有茶喝了");
                }
                return waterOk && cupOk;
            }
        }, jPool);
        try {
            Boolean result = teaFuture.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
